package org.ccay.web.support.internal.impl;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.ccay.core.ioc.Ccay;
import org.ccay.core.request.Application;
import org.ccay.core.request.impl.RequestContextConstants;
import org.ccay.core.util.CollectionUtil;
import org.ccay.core.util.EncodingUtil;
import org.ccay.core.util.MimeTypeUtil;
import org.ccay.core.util.StringUtil;
import org.ccay.web.support.EnvironmentBean;
import org.ccay.web.support.WebRequestVO;

/**
 * 请求处理 辅助类
 * 
 * 
 * @since 2012-4-6
 */
public final class RequestUtil {
 	/**
	 * 80端口
	 */
	private static final int PORT_80 = 80;
	/**
	 * Session 掩码长度
	 */
	private static final int MASK_LENGTH = 6;
	/**
	 * COOKIE有效期，鉴于工号切换为8年，此处设置为8年，包含两个闰2月
	 */
	private static final int MAX_COOKIE_AGE = (8*365+2)*24*3600;
	/**
	 * 默认时间误差
	 */
	static final int TIME_BUFFER = 1000;
	
	/**
	 * 浏览器缓存文件更新时间戳名字
	 */
	private static final String IF_MODIFIED_SINCE_NAME = "If-Modified-Since";
	/**
	 * 主机名
	 */
	private static String hostName = null;
	
	/**
	 * 服务器名称
	 */
	private static String serverName = null;
	
	/**
	 * 上下文根是否已经设置到Application中
	 */
	private static boolean contextPathInitialized = false ;
	
	@Inject
	//ccay.web.support.beans.xml 配置
	private static HashSet<String> htmlResponseUrlSet ;

	
	@SuppressWarnings("unchecked")
	public static Set<String> getHtmlResponseUrlSet() {
		if(CollectionUtil.isNullOrEmpty(htmlResponseUrlSet)){
			htmlResponseUrlSet = Ccay.getContext().getBean("ccayHtmlResponseUrl", HashSet.class);
		}
		return htmlResponseUrlSet;
	}

	public static String getServerName() {
		return serverName;
	}
	/**
	 * @return the hostName
	 */
	public static String getHostName() {
		return hostName;
	}
	/**
	 * @param hostName the hostName to set
	 */
	public static void setHostName(String hostName) {
		
		RequestUtil.serverName = hostName;
		if (hostName == null) {
			hostName = "";
		}
		RequestUtil.hostName = hostName.lastIndexOf("-") != -1 ? hostName.substring(0, hostName.lastIndexOf("-")) : hostName;
		
	}
	private RequestUtil() {
	}
	/**
	 * 检查是否需要加载资源
	 * @param webRequest
	 * @param exclusions
	 * @return
	 */
	public static boolean isExclude(WebRequestVO webRequest,String[] exclusions)
	 {
		//没有文件类型的 不处理
		if(webRequest.getFileType() == null){
			 return true;
		}
		String currentURL = webRequest.getShortUri();
	     if (StringUtil.isNullOrEmpty(currentURL) || CollectionUtil.isNullOrEmpty(exclusions)) {
	    	return false;
		 }
	     //检查当前url是否有包含 不许要加载资源的路径
	     for (int i = 0; i < exclusions.length; ++i) {
	       if (currentURL.startsWith(exclusions[i])) {
	         return true;
	       }
	     }
	    return false;
	}
	
	/** 
	 * 是否受保护的请求（要求构建安全上下文）
	 * @param webRequest
	 * @return
	 */
	public static boolean isProtectedResource(WebRequestVO webRequest, String[] publices){
		String uri = webRequest.getShortUri();
		if(CollectionUtil.isNullOrEmpty(publices)){
			return false;
		}
		//检查当前url是否有包含 不需要验证权限的路径
		for (int i = 0; i < publices.length; ++i) {
		       if (uri.startsWith(publices[i])) {
		         return false;
		       }
		}
		if("html".equals(webRequest.getFileType())){
			return true;
		}
		return false;
	} 
	
	/** 
	 * 获取SessionID，NULL时返回N/A
	 * @param request
	 * @return
	 */
	public static String getSessionId(HttpServletRequest request) {
		//Use Shior Session
		Session session = SecurityUtils.getSubject().getSession(false);
		//HttpSession session = request.getSession(false);
		return session != null ?session.getId().toString():"N/A";
	}
	
	/** 
	 * 获取SessionID的掩码，用于日志记录（不暴露完整的SessionID），NULL时返回N/A
	 * @param request
	 * @return
	 */
	public static String getSessionIdMask(HttpServletRequest request) {
		String sessionId = getSessionId(request);
		if(sessionId.equals("N/A")){
			return sessionId;
		}
		return sessionId.substring(sessionId.length()-MASK_LENGTH);
	}
	
	/** 
	 * 获取会话重建URL
	 * @param request
	 * @return
	 */
	public static String getSessionRebuildUrl(HttpServletRequest request){
		return getRootUrl(request) +"servlet/rebuildSession";
	}
	
	/**
	 * 获取以 / 结尾的上下文根
	 * @param request
	 */
	public static String getContextPath(HttpServletRequest request) {
		return getContextPath(request.getContextPath());
		
	}
	
	/**  T
	 * 获取以 / 结尾的上下文根
	 * @param contextPath
	 * @return
	 */
	public static String getContextPath(String contextPath) {
		if (null == contextPath) {
			return contextPath;
		}
		
		if(!contextPath.endsWith("/")){
			contextPath = contextPath+"/";
		}
		
		return contextPath;
	}
	

	
	private static String rootUrl ;
	/**
	 * 获取应用的根URL
	 * @param request
	 * @return
	 */
	public static String getRootUrl(HttpServletRequest request){
		if (rootUrl == null) {

			int remotePort = request.getServerPort();
			rootUrl = MessageFormat.format("{0}://{1}{2}{3}", request.getScheme(), request.getServerName(),
					(remotePort == PORT_80 ? "" : ":" + remotePort), getContextPath(request));
		}
		
		return rootUrl;
	}
	
	/** 
	 * 判断是否在访问首页
	 * @param request
	 * @return
	 */
	public static boolean isHomePage(HttpServletRequest request){
		String requestURI = getShortUri(request);
		return isHomePage(requestURI);
	}
	
	/**
	 * 判断是否在访问首页
	 * @param requestURI
	 * @return
	 */
	public static boolean isHomePage(String requestURI) {
		return "/".equals(requestURI) || "/index.html".equals(requestURI) || "/index_dev.html".equals(requestURI);

	}
	
	/** 
	 * 是否为直接上下文根，不带具体路径的访问	
	 * 
	 * @since 2012-8-16
	 * @param shortUri
	 * @return
	 */
	public static boolean isRootAccess(String shortUri) {
		return "/".equals(shortUri) || shortUri.length() == 0;
	}
	
	private static Set<String> noneResourceUri = new HashSet<String>();
	
	static{
		noneResourceUri.add(RequestContextConstants.TYPE_SERVLET);
		noneResourceUri.add(RequestContextConstants.TYPE_PRIVATE_SERVICES);
		noneResourceUri.add(RequestContextConstants.TYPE_PUBLIC_SERVICES);
		noneResourceUri.add(RequestContextConstants.TYPE_INTERNAL_SERVICES);
	}

	/** 
	 * 是否资源
	 * @param request
	 * @return
	 */
	public static boolean isResource(HttpServletRequest request) {
		return RequestContextConstants.TYPE_RESOURCES.equals(getRequestType(request));
	}
	
	/** 
	 * 获取短的URI，不包含上下文根，含有前面的/
	 * @param req
	 * @return
	 */
	public static String getShortUri(HttpServletRequest req) {
		String shortUri = (String)req.getAttribute(RequestContextConstants.KEY_URI);
		if( shortUri != null){
			return shortUri;
		}
		
		String uri = req.getRequestURI();
		String cxt = req.getContextPath();
		
		if(StringUtil.isNullOrEmpty(uri) || uri.length() == cxt.length()){
			shortUri = StringUtil.EMPTY;
		}else if(cxt.length()>0){
			shortUri = uri.substring(cxt.length());
		}
		
		req.setAttribute(RequestContextConstants.KEY_URI, shortUri);
		
		return shortUri;
	}
	
	/** 
	 * 获得URI的第一部分
	 * @param req
	 * @return
	 */
	public static String getFirstPartOfUri(HttpServletRequest req){
		String shortUri = getShortUri(req);
		
		int indexOfSlash = shortUri.indexOf("/", 1);
		
		if(indexOfSlash >= 1){
			return shortUri.substring(1,indexOfSlash);
		}else{
			return shortUri;
		}
	}
	
	/**
	 * 是否会话重建页面
	 * @param request
	 * @return
	 */
	public static boolean isSessionRebuildPage(HttpServletRequest request) {
		return "/servlet/rebuildSession".equals(getShortUri(request));
	}
	
	/** 
	 * 清空Session
	 * @param request
	 */
	public static void clearSession(HttpServletRequest request) {
		//Use Shior Session
		 Session session = SecurityUtils.getSubject().getSession(false);
		if(session!=null){
			session.stop();
		}
	} 
	
	/** 
	 * 获取Cookie值，不存在时返回NULL
	 * @param key
	 */
	public static String getCookieValue(HttpServletRequest request, String key){
		Cookie[] cookies = request.getCookies();
		
		if(cookies == null){
			return null;
		}
		
		for(Cookie cookie : cookies){
			if(cookie.getName().equalsIgnoreCase(key)){
				return cookie.getValue();
			}
		}
		
		return null;
	}
	
	public static void setCookieValue(HttpServletRequest request, HttpServletResponse response , String key, String value){
		Cookie cookie = new Cookie(key, value);
		//默认设置在当前上下文根
		cookie.setPath(request.getContextPath());
		cookie.setMaxAge(MAX_COOKIE_AGE);
		response.addCookie(cookie);
	}
	
	/**
	 * 根据请求组装cookie信息
	 * @param request
	 * @return
	 */
	public static String getCookies(HttpServletRequest request) {
		StringBuffer sb = new StringBuffer();
		Cookie[] cks = request.getCookies();
		if (cks != null) {
			for (int i = 0; i < cks.length; i++) {
				sb.append(cks[i].getName());
				sb.append("=");
				sb.append(cks[i].getValue());
				sb.append(";");
			}
			return sb.toString();
		}

		return "";
	}
	
	/** 
	 * 设置Session值
	 * @param request
	 * @param key
	 * @param value
	 */
	public static void setSessionValue(HttpServletRequest request, String key, Object value){
		//Use Shior Session
		SecurityUtils.getSubject().getSession(true).setAttribute(key, value);
	}
	
	/** 
	 * 获取Session值，Session不存在或者Key不存在时返回NULL
	 * @param request
	 * @param key
	 * @return
	 */
	public static Object getSessionValue(HttpServletRequest request, String key){
		//HttpSession session = request.getSession(false);
		//Use Shior Session
		Session session = SecurityUtils.getSubject().getSession(false);
		if(session== null){
			 return null;
		}
		
		return session.getAttribute(key);		
	}
	
	/** 
	 * 
	 * @param request
	 * @return
	 */
	public static boolean isAjaxRequest(HttpServletRequest request) {
		return "XMLHttpRequest".equals(request.getHeader("x-requested-with"));
	}
	
	/** 
	 * 是否需要响应文本
	 * @param req
	 * @return
	 */
	public static boolean isHtmlResponse(HttpServletRequest req, ServletResponse res) {
		String uri = getShortUri(req); 
		
		if(uri.equals("/servlet/upload")){
			return false;
		}
		/**
		 * 配置文件的响应
		 */
		for(String url :getHtmlResponseUrlSet()){
			if(uri.startsWith(url)){
				return true;
			}
		}
		
		
		return (uri.length() <= 1 ||  uri.endsWith(".html") 
				|| MimeTypeUtil.getTypeBySuffix("html").equals(res.getContentType())
				|| Boolean.TRUE.equals(req.getAttribute(CCAY_IS_HTML_RESPONSE)));
	}
	
	private static final String CCAY_IS_HTML_RESPONSE = "CCAY_IS_HTML";
	/** 
	 * 设置为在出错时需要相应Html	
	 * 
	 * @since 2013-2-1
	 * @param req
	 */
	public static void setOnErrorResponseHtml(ServletRequest req){		
		req.setAttribute(CCAY_IS_HTML_RESPONSE, true );
	}
	/** 
	 * 获取Request中的URI以斜杠分割的数组	
	 * 
	 * @since 2012-6-26
	 * @param request
	 * @return
	 */
	public static String[] getRequestUriParts(HttpServletRequest request) {
	    return RequestUtil.getShortUri(request).split("/");
	}
	
	/**
	 * 获取GET请求的查询参数，并对中文参数进行解码处理
	 * 
	 * @since 2014-8-30
	 * @param request
	 * @return GET请求的查询参数集合
	 */
	public static Map<String, String> getRequestQueryParams(HttpServletRequest request){
		String query = request.getQueryString();
		Map<String, String> parameters = new HashMap<String, String>();
		if(!StringUtil.isNullOrEmpty(query)){
			String[] paramPairs = StringUtil.tokenizeToStringArray(query, "&");
			for (String paramPair : paramPairs) {
				int indexOfSplit = paramPair.indexOf("=");
				if(indexOfSplit > -1){
					String paramKey = paramPair.substring(0, indexOfSplit);
					String paramValue = paramPair.substring(indexOfSplit + 1);
					try {
						paramValue = URLDecoder.decode(paramValue, EncodingUtil.UTF_8);
					} catch (UnsupportedEncodingException e) {
					}
					parameters.put(paramKey, paramValue);
				}
			}
		}
		return parameters;
	}
	
	/** 
	 * 初始化请求类型
	 * @param httpReq
	 */
	public static void initRequestAttributes(HttpServletRequest httpReq) {
		String firstPart = getFirstPartOfUri(httpReq);
		
		if(noneResourceUri.contains(firstPart)){
			httpReq.setAttribute(RequestContextConstants.KEY_REQUEST_TYPE, firstPart);
		}else{
			httpReq.setAttribute(RequestContextConstants.KEY_REQUEST_TYPE, RequestContextConstants.TYPE_RESOURCES);
		}		
	}
	
	/** 
	 * 获取请求类型
	 * @param httpReq
	 * @return
	 */
	public static String getRequestType(HttpServletRequest httpReq){
		return (String) httpReq.getAttribute(RequestContextConstants.KEY_REQUEST_TYPE);
	}
	/** 
	 * 计算文件是否修改
	 * @param clientModifiedTime
	 * @param serverModifiedTime
	 * @return
	 */
	public static boolean isNotModified(long clientModifiedTime, long serverModifiedTime) {
		//取绝对值，因为文件可能被回滚
		return clientModifiedTime >0 && Math.abs(serverModifiedTime-clientModifiedTime) <= RequestUtil.TIME_BUFFER;
	}
	
	/** 
	 * 获取修改时间戳	
	 * 
	 * @since 2013-3-7
	 * @param request
	 * @return
	 */
	public static long getModifiedTimestamp(HttpServletRequest request){
		return request.getDateHeader(IF_MODIFIED_SINCE_NAME);		
	}
	private static volatile EnvironmentBean env;
	/**
	 * 根据当前内外网环境读取参数
	 * 
	 * 
	 * @return envBean
	 */
	public static EnvironmentBean getEnvBeanByNetwrok() {		 
		if(env != null){
			return env;
		}
		
		if ("internet".equalsIgnoreCase(Application.getCurrent().getNetwork())) {
			env= Ccay.getContext().getBean("environmentBean.internet", EnvironmentBean.class);
		} else {
			env= Ccay.getContext().getBean("environmentBean", EnvironmentBean.class);
		}
		
		return env;
	}
	
	/** 
	 * 获取机器名中的数字部分。
	 * @param hostName
	 * @return
	 */
	private static String getNumbers(String hostName) {
		StringBuilder num = new StringBuilder();
		for(char c : hostName.toCharArray()){
			if(Character.isDigit(c)){
				num.append(c);
			}
		}
		return num.toString();
	}

	public static boolean isContextPathInitialized() {
		return contextPathInitialized;
	}

	public static void setContextPathInitialized(boolean contextPathInitialized) {
		RequestUtil.contextPathInitialized = contextPathInitialized;
	}
	
	
}
